Build the phys_to_machine_mapping array in Xen rather than
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 3 Feb 2006 11:02:30 +0000 (12:02 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 3 Feb 2006 11:02:30 +0000 (12:02 +0100)
reusing the 1:1 page table built by the builder, and it also establishes
the 1:1 direct mapping at runtime a la shadow page tables. Since the
builder constructs the full 1:1 direct mapping (but <4GB), the current
implementation wastes memory but cannot support guests with >=4GB
memory (even for x64-64).

This is also required for HVM support on the PAE host. That patch
should be sent soon.

For SVM, I think the svm code needs changes. Please look at the changes
to vmx.c and vmcs.c; should be straightforward.

Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
Signed-off-by: Xiaohui Xin <xiaohui.xin@intel.com>
tools/libxc/xc_hvm_build.c
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/shadow.c
xen/arch/x86/shadow32.c
xen/arch/x86/shadow_public.c
xen/include/asm-x86/mm.h
xen/include/asm-x86/shadow.h
xen/include/asm-x86/shadow_64.h
xen/include/asm-x86/shadow_public.h

index 086adbb181d5136bc2bb4abf8098cb2ab8a0d19c..173f091d8c7f47421c10418c240864b1d6be7f89 100644 (file)
@@ -168,133 +168,6 @@ static int set_hvm_info(int xc_handle, uint32_t dom,
     return 0;
 }
 
-#ifdef __i386__
-static int zap_mmio_range(int xc_handle, uint32_t dom,
-                          l2_pgentry_32_t *vl2tab,
-                          unsigned long mmio_range_start,
-                          unsigned long mmio_range_size)
-{
-    unsigned long mmio_addr;
-    unsigned long mmio_range_end = mmio_range_start + mmio_range_size;
-    unsigned long vl2e;
-    l1_pgentry_32_t *vl1tab;
-
-    mmio_addr = mmio_range_start & PAGE_MASK;
-    for (; mmio_addr < mmio_range_end; mmio_addr += PAGE_SIZE) {
-        vl2e = vl2tab[l2_table_offset(mmio_addr)];
-        if (vl2e == 0)
-            continue;
-        vl1tab = xc_map_foreign_range(
-            xc_handle, dom, PAGE_SIZE,
-            PROT_READ|PROT_WRITE, vl2e >> PAGE_SHIFT);
-        if ( vl1tab == 0 )
-        {
-            PERROR("Failed zap MMIO range");
-            return -1;
-        }
-        vl1tab[l1_table_offset(mmio_addr)] = 0;
-        munmap(vl1tab, PAGE_SIZE);
-    }
-    return 0;
-}
-
-static int zap_mmio_ranges(int xc_handle, uint32_t dom, unsigned long l2tab,
-                           unsigned char e820_map_nr, unsigned char *e820map)
-{
-    unsigned int i;
-    struct e820entry *e820entry = (struct e820entry *)e820map;
-
-    l2_pgentry_32_t *vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                                   PROT_READ|PROT_WRITE,
-                                                   l2tab >> PAGE_SHIFT);
-    if ( vl2tab == 0 )
-        return -1;
-
-    for ( i = 0; i < e820_map_nr; i++ )
-    {
-        if ( (e820entry[i].type == E820_IO) &&
-             (zap_mmio_range(xc_handle, dom, vl2tab,
-                             e820entry[i].addr, e820entry[i].size) == -1))
-            return -1;
-    }
-
-    munmap(vl2tab, PAGE_SIZE);
-    return 0;
-}
-#else
-static int zap_mmio_range(int xc_handle, uint32_t dom,
-                          l3_pgentry_t *vl3tab,
-                          unsigned long mmio_range_start,
-                          unsigned long mmio_range_size)
-{
-    unsigned long mmio_addr;
-    unsigned long mmio_range_end = mmio_range_start + mmio_range_size;
-    unsigned long vl2e = 0;
-    unsigned long vl3e;
-    l1_pgentry_t *vl1tab;
-    l2_pgentry_t *vl2tab;
-
-    mmio_addr = mmio_range_start & PAGE_MASK;
-    for ( ; mmio_addr < mmio_range_end; mmio_addr += PAGE_SIZE )
-    {
-        vl3e = vl3tab[l3_table_offset(mmio_addr)];
-        if ( vl3e == 0 )
-            continue;
-
-        vl2tab = xc_map_foreign_range(
-            xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, vl3e>>PAGE_SHIFT);
-        if ( vl2tab == NULL )
-        {
-            PERROR("Failed zap MMIO range");
-            return -1;
-        }
-
-        vl2e = vl2tab[l2_table_offset(mmio_addr)];
-        if ( vl2e == 0 )
-        {
-            munmap(vl2tab, PAGE_SIZE);
-            continue;
-        }
-
-        vl1tab = xc_map_foreign_range(
-            xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, vl2e>>PAGE_SHIFT);
-        if ( vl1tab == NULL )
-        {
-            PERROR("Failed zap MMIO range");
-            munmap(vl2tab, PAGE_SIZE);
-            return -1;
-        }
-
-        vl1tab[l1_table_offset(mmio_addr)] = 0;
-        munmap(vl2tab, PAGE_SIZE);
-        munmap(vl1tab, PAGE_SIZE);
-    }
-    return 0;
-}
-
-static int zap_mmio_ranges(int xc_handle, uint32_t dom, unsigned long l3tab,
-                           unsigned char e820_map_nr, unsigned char *e820map)
-{
-    unsigned int i;
-    struct e820entry *e820entry = (struct e820entry *)e820map;
-
-    l3_pgentry_t *vl3tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                                PROT_READ|PROT_WRITE,
-                                                l3tab >> PAGE_SHIFT);
-    if (vl3tab == 0)
-        return -1;
-    for ( i = 0; i < e820_map_nr; i++ ) {
-        if ( (e820entry[i].type == E820_IO) &&
-             (zap_mmio_range(xc_handle, dom, vl3tab,
-                             e820entry[i].addr, e820entry[i].size) == -1) )
-            return -1;
-    }
-    munmap(vl3tab, PAGE_SIZE);
-    return 0;
-}
-
-#endif
-
 static int setup_guest(int xc_handle,
                        uint32_t dom, int memsize,
                        char *image, unsigned long image_size,
@@ -308,15 +181,8 @@ static int setup_guest(int xc_handle,
                        unsigned int store_evtchn,
                        unsigned long *store_mfn)
 {
-    l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
-    l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
     unsigned long *page_array = NULL;
-#ifdef __x86_64__
-    l3_pgentry_t *vl3tab=NULL;
-    unsigned long l3tab;
-#endif
-    unsigned long l2tab = 0;
-    unsigned long l1tab = 0;
+
     unsigned long count, i;
     shared_info_t *shared_info;
     void *e820_page;
@@ -325,7 +191,6 @@ static int setup_guest(int xc_handle,
     int rc;
 
     unsigned long nr_pt_pages;
-    unsigned long ppt_alloc;
 
     struct domain_setup_info dsi;
     unsigned long vpt_start;
@@ -391,120 +256,6 @@ static int setup_guest(int xc_handle,
     if ( (mmu = xc_init_mmu_updates(xc_handle, dom)) == NULL )
         goto error_out;
 
-    /* First allocate page for page dir or pdpt */
-    ppt_alloc = vpt_start >> PAGE_SHIFT;
-    if ( page_array[ppt_alloc] > 0xfffff )
-    {
-        unsigned long nmfn;
-        nmfn = xc_make_page_below_4G( xc_handle, dom, page_array[ppt_alloc] );
-        if ( nmfn == 0 )
-        {
-            fprintf(stderr, "Couldn't get a page below 4GB :-(\n");
-            goto error_out;
-        }
-        page_array[ppt_alloc] = nmfn;
-    }
-
-#ifdef __i386__
-    l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
-    ctxt->ctrlreg[3] = l2tab;
-
-    if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                        PROT_READ|PROT_WRITE,
-                                        l2tab >> PAGE_SHIFT)) == NULL )
-        goto error_out;
-    memset(vl2tab, 0, PAGE_SIZE);
-    vl2e = &vl2tab[l2_table_offset(0)];
-    for ( count = 0; count < (v_end >> PAGE_SHIFT); count++ )
-    {
-        if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
-        {
-            l1tab = page_array[ppt_alloc++] << PAGE_SHIFT;
-            if ( vl1tab != NULL )
-                munmap(vl1tab, PAGE_SIZE);
-            if ( (vl1tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                                PROT_READ|PROT_WRITE,
-                                                l1tab >> PAGE_SHIFT)) == NULL )
-            {
-                munmap(vl2tab, PAGE_SIZE);
-                goto error_out;
-            }
-            memset(vl1tab, 0, PAGE_SIZE);
-            vl1e = &vl1tab[l1_table_offset(count << PAGE_SHIFT)];
-            *vl2e++ = l1tab | L2_PROT;
-        }
-
-        *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
-        vl1e++;
-    }
-    munmap(vl1tab, PAGE_SIZE);
-    munmap(vl2tab, PAGE_SIZE);
-#else
-    l3tab = page_array[ppt_alloc++] << PAGE_SHIFT;
-    ctxt->ctrlreg[3] = l3tab;
-
-    if ( (vl3tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                        PROT_READ|PROT_WRITE,
-                                        l3tab >> PAGE_SHIFT)) == NULL )
-        goto error_out;
-    memset(vl3tab, 0, PAGE_SIZE);
-
-    /* Fill in every PDPT entry. */
-    for ( i = 0; i < L3_PAGETABLE_ENTRIES_PAE; i++ )
-    {
-        l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
-        if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                            PROT_READ|PROT_WRITE,
-                                            l2tab >> PAGE_SHIFT)) == NULL )
-            goto error_out;
-        memset(vl2tab, 0, PAGE_SIZE);
-        munmap(vl2tab, PAGE_SIZE);
-        vl2tab = NULL;
-        vl3tab[i] = l2tab | L3_PROT;
-    }
-
-    for ( count = 0; count < (v_end >> PAGE_SHIFT); count++ )
-    {
-        if ( !(count & ((1 << (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)) - 1)) )
-        {
-            l2tab = vl3tab[count >> (L3_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)]
-                    & PAGE_MASK;
-
-            if (vl2tab != NULL)
-                munmap(vl2tab, PAGE_SIZE);
-
-            if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                                PROT_READ|PROT_WRITE,
-                                                l2tab >> PAGE_SHIFT)) == NULL )
-                goto error_out;
-
-            vl2e = &vl2tab[l2_table_offset(count << PAGE_SHIFT)];
-        }
-        if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
-        {
-            l1tab = page_array[ppt_alloc++] << PAGE_SHIFT;
-            if ( vl1tab != NULL )
-                munmap(vl1tab, PAGE_SIZE);
-            if ( (vl1tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
-                                                PROT_READ|PROT_WRITE,
-                                                l1tab >> PAGE_SHIFT)) == NULL )
-            {
-                munmap(vl2tab, PAGE_SIZE);
-                goto error_out;
-            }
-            memset(vl1tab, 0, PAGE_SIZE);
-            vl1e = &vl1tab[l1_table_offset(count << PAGE_SHIFT)];
-            *vl2e++ = l1tab | L2_PROT;
-        }
-
-        *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
-        vl1e++;
-    }
-
-    munmap(vl1tab, PAGE_SIZE);
-    munmap(vl2tab, PAGE_SIZE);
-    munmap(vl3tab, PAGE_SIZE);
-#endif
     /* Write the machine->phys table entries. */
     for ( count = 0; count < nr_pages; count++ )
     {
@@ -525,14 +276,6 @@ static int setup_guest(int xc_handle,
         goto error_out;
     memset(e820_page, 0, PAGE_SIZE);
     e820_map_nr = build_e820map(e820_page, v_end);
-#if defined (__i386__)
-    if (zap_mmio_ranges(xc_handle, dom, l2tab, e820_map_nr,
-                        ((unsigned char *)e820_page) + E820_MAP_OFFSET) == -1)
-#else
-    if (zap_mmio_ranges(xc_handle, dom, l3tab, e820_map_nr,
-                        ((unsigned char *)e820_page) + E820_MAP_OFFSET) == -1)
-#endif
-        goto error_out;
     munmap(e820_page, PAGE_SIZE);
 
     /* shared_info page starts its life empty. */
index a15caff3907b338bb0e3a74a8a15bc321c51f9cd..38772b5d41bc3922c90352b1a702db20b6e7dc1b 100644 (file)
@@ -53,6 +53,20 @@ integer_param("hvm_debug", opt_hvm_debug_level);
 
 struct hvm_function_table hvm_funcs;
 
+static void vmx_zap_mmio_range(
+    struct domain *d, unsigned long pfn, unsigned long nr_pfn)
+{
+    unsigned long i, val = INVALID_MFN;
+
+    for ( i = 0; i < nr_pfn; i++ )
+    {
+        if ( pfn + i >= 0xfffff ) 
+            break;
+        
+        __copy_to_user(&phys_to_machine_mapping[pfn + i], &val, sizeof (val));
+    }
+}
+
 static void hvm_map_io_shared_page(struct domain *d)
 {
     int i;
@@ -84,8 +98,12 @@ static void hvm_map_io_shared_page(struct domain *d)
         if (e820entry[i].type == E820_SHARED_PAGE)
         {
             gpfn = (e820entry[i].addr >> PAGE_SHIFT);
-            break;
         }
+        if ( e820entry[i].type == E820_IO )
+            vmx_zap_mmio_range(
+                d, 
+                e820entry[i].addr >> PAGE_SHIFT,
+                e820entry[i].size >> PAGE_SHIFT);
     }
 
     if ( gpfn == 0 ) {
index 2915a62c4cb2ae723d9b1b81ff2e523a9c1f42a8..cf81907d364c21da8c82d820ddcc4fe8e3f1e469 100644 (file)
@@ -34,7 +34,8 @@
 #include <asm/flushtlb.h>
 #include <xen/event.h>
 #include <xen/kernel.h>
-#if CONFIG_PAGING_LEVELS >= 4
+#include <asm/shadow.h>
+#if CONFIG_PAGING_LEVELS >= 3
 #include <asm/shadow_64.h>
 #endif
 
@@ -218,6 +219,7 @@ static void vmx_do_launch(struct vcpu *v)
     error |= __vmwrite(GUEST_TR_BASE, 0);
     error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
 
+    shadow_direct_map_init(v);
     __vmwrite(GUEST_CR3, pagetable_get_paddr(v->domain->arch.phys_table));
     __vmwrite(HOST_CR3, pagetable_get_paddr(v->arch.monitor_table));
     __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom());
index 01fda3e24dc94633bc33383634726630444c3625..1202ea64bb8fda56aa6ca8abbb40a190ef6f07a9 100644 (file)
@@ -563,7 +563,12 @@ static int vmx_do_page_fault(unsigned long va, struct cpu_user_regs *regs)
     }
 #endif
 
-    if (!vmx_paging_enabled(current)){
+    if ( !vmx_paging_enabled(current) )
+    {
+        /* construct 1-to-1 direct mapping */
+        if ( shadow_direct_map_fault(va, regs) ) 
+            return 1;
+
         handle_mmio(va, va);
         TRACE_VMEXIT (2,2);
         return 1;
@@ -1212,6 +1217,9 @@ static int vmx_set_cr0(unsigned long value)
                 __vmwrite(GUEST_CR4, crn | X86_CR4_PAE);
             }
         }
+#endif
+#if CONFIG_PAGING_LEVELS == 2
+        shadow_direct_map_clean(v);
 #endif
         /*
          * Now arch.guest_table points to machine physical.
index 26b90817261bee8e491edf5634f02e91d589c4ba..81ff8a5aa641b989dc2bf01b950fc71170e0662f 100644 (file)
@@ -2858,7 +2858,7 @@ static inline unsigned long init_bl2(l4_pgentry_t *spl4e, unsigned long smfn)
     if (!page)
         domain_crash_synchronous();
 
-    for (count = 0; count < PDP_ENTRIES; count++)
+    for ( count = 0; count < PAE_L3_PAGETABLE_ENTRIES; count++ )
     {
         sl2mfn = page_to_mfn(page+count);
         l2 = map_domain_page(sl2mfn);
@@ -3568,6 +3568,7 @@ static void shadow_invlpg_64(struct vcpu *v, unsigned long va)
     shadow_unlock(d);
 }
 
+
 #if CONFIG_PAGING_LEVELS == 4
 static unsigned long gva_to_gpa_64(unsigned long gva)
 {
@@ -3637,6 +3638,79 @@ struct shadow_ops MODE_B_HANDLER = {
 
 #endif
 
+#if CONFIG_PAGING_LEVELS == 3 ||                                \
+    ( CONFIG_PAGING_LEVELS == 4 && defined (GUEST_PGENTRY_32) )
+
+/* 
+ * Use GUEST_PGENTRY_32 to force PAE_SHADOW_SELF_ENTRY for L4.
+ *
+ * Very simple shadow code to handle 1:1 direct mapping for guest 
+ * non-paging code, which actually is running in PAE/vm86 mode with 
+ * paging-enabled.
+ *
+ * We expect that the top level (L3) page has been allocated and initialized.
+ */
+int shadow_direct_map_fault(unsigned long vpa, struct cpu_user_regs *regs)
+{
+    struct vcpu *v = current;
+    struct domain *d = v->domain;
+    l3_pgentry_t sl3e;
+    l2_pgentry_t sl2e;
+    l1_pgentry_t sl1e;
+    unsigned long mfn, smfn;
+    struct page_info *page;
+
+    /*
+     * If the faulting address is within the MMIO range, we continue
+     * on handling the #PF as such.
+     */
+    if ( (mfn = get_mfn_from_gpfn(vpa >> PAGE_SHIFT)) == INVALID_MFN )
+    {
+         goto fail;
+    }
+
+    shadow_lock(d);
+
+    __shadow_get_l3e(v, vpa, &sl3e);
+
+    if ( !(l3e_get_flags(sl3e) & _PAGE_PRESENT) ) 
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto fail; 
+        smfn = page_to_mfn(page);
+        sl3e = l3e_from_pfn(smfn, _PAGE_PRESENT);
+        __shadow_set_l3e(v, vpa, &sl3e);
+    }
+
+    __shadow_get_l2e(v, vpa, &sl2e);
+
+    if ( !(l2e_get_flags(sl2e) & _PAGE_PRESENT) ) 
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto fail; 
+        smfn = page_to_mfn(page);
+
+        sl2e = l2e_from_pfn(smfn, __PAGE_HYPERVISOR | _PAGE_USER);
+        __shadow_set_l2e(v, vpa, &sl2e);
+    }
+
+    __shadow_get_l1e(v, vpa, &sl1e);
+        
+    if ( !(l1e_get_flags(sl1e) & _PAGE_PRESENT) ) 
+    {
+        sl1e = l1e_from_pfn(mfn, __PAGE_HYPERVISOR | _PAGE_USER);
+        __shadow_set_l1e(v, vpa, &sl1e);
+    } 
+
+    shadow_unlock(d);
+    return EXCRET_fault_fixed;
+
+fail:
+    return 0;
+}
+#endif
 
 /*
  * Local variables:
index a4df3c93243cb0f6bfa0575bd2e37d2edac28e81..c7475cfaf037be0c577b7931f423bbceb57ecefe 100644 (file)
@@ -43,6 +43,8 @@ static void free_writable_pte_predictions(struct domain *d);
 static void mark_shadows_as_reflecting_snapshot(struct domain *d, unsigned long gpfn);
 #endif
 
+static void free_p2m_table(struct vcpu *v);
+
 /********
 
 There's a per-domain shadow table spin lock which works fine for SMP
@@ -746,19 +748,18 @@ static void alloc_monitor_pagetable(struct vcpu *v)
             l2e_from_page(virt_to_page(d->arch.mm_perdomain_pt) + i,
                           __PAGE_HYPERVISOR);
 
-    // map the phys_to_machine map into the Read-Only MPT space for this domain
-    mpl2e[l2_table_offset(RO_MPT_VIRT_START)] =
-        l2e_from_paddr(pagetable_get_paddr(d->arch.phys_table),
-                        __PAGE_HYPERVISOR);
-
     // Don't (yet) have mappings for these...
     // Don't want to accidentally see the idle_pg_table's linear mapping.
     //
     mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)] = l2e_empty();
     mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] = l2e_empty();
+    mpl2e[l2_table_offset(RO_MPT_VIRT_START)] = l2e_empty();
 
     v->arch.monitor_table = mk_pagetable(mmfn << PAGE_SHIFT);
     v->arch.monitor_vtable = mpl2e;
+
+    if ( v->vcpu_id == 0 )
+        alloc_p2m_table(d);
 }
 
 /*
@@ -792,6 +793,9 @@ void free_monitor_pagetable(struct vcpu *v)
         put_shadow_ref(mfn);
     }
 
+    if ( v->vcpu_id == 0 )
+        free_p2m_table(v);
+
     /*
      * Then free monitor_table.
      */
@@ -844,67 +848,209 @@ set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn,
     return 1;
 }
 
-static int
+int
 alloc_p2m_table(struct domain *d)
 {
     struct list_head *list_ent;
-    struct page_info *page, *l2page;
-    l2_pgentry_t *l2;
-    unsigned long mfn, pfn;
-    struct domain_mmap_cache l1cache, l2cache;
+    unsigned long va = RO_MPT_VIRT_START;   /* phys_to_machine_mapping */
 
-    l2page = alloc_domheap_page(NULL);
-    if ( l2page == NULL )
-        return 0;
+    l2_pgentry_t *l2tab = NULL;
+    l1_pgentry_t *l1tab = NULL;
+    unsigned long *l0tab = NULL;
+    l2_pgentry_t l2e = { 0 };
+    l1_pgentry_t l1e = { 0 };
+
+    unsigned long pfn;
+    int i;
 
-    domain_mmap_cache_init(&l1cache);
-    domain_mmap_cache_init(&l2cache);
+    ASSERT ( pagetable_get_pfn(d->vcpu[0]->arch.monitor_table));
 
-    d->arch.phys_table = mk_pagetable(page_to_maddr(l2page));
-    l2 = map_domain_page_with_cache(page_to_mfn(l2page), &l2cache);
-    memset(l2, 0, PAGE_SIZE);
-    unmap_domain_page_with_cache(l2, &l2cache);
+    l2tab = map_domain_page(
+        pagetable_get_pfn(d->vcpu[0]->arch.monitor_table));
 
     list_ent = d->page_list.next;
-    while ( list_ent != &d->page_list )
+
+    for ( i = 0; list_ent != &d->page_list; i++ )
     {
+        struct page_info *page;
         page = list_entry(list_ent, struct page_info, list);
-        mfn = page_to_mfn(page);
-        pfn = get_gpfn_from_mfn(mfn);
-        ASSERT(pfn != INVALID_M2P_ENTRY);
-        ASSERT(pfn < (1u<<20));
+        pfn = page_to_mfn(page);
 
-        set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache);
+        l2e = l2tab[l2_table_offset(va)];
+        if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
+        {
+            page = alloc_domheap_page(NULL);
+
+            if ( !l1tab )
+                unmap_domain_page(l1tab);
+            l1tab = map_domain_page(page_to_mfn(page));
+            memset(l1tab, 0, PAGE_SIZE);
+            l2e = l2tab[l2_table_offset(va)] =
+                l2e_from_page(page, __PAGE_HYPERVISOR);
+        }
+        else if ( l1tab == NULL)
+            l1tab = map_domain_page(l2e_get_pfn(l2e));
 
-        list_ent = page->list.next;
+        l1e = l1tab[l1_table_offset(va)];
+        if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) )
+        {
+            page = alloc_domheap_page(NULL);
+            if ( !l0tab  )
+                unmap_domain_page(l0tab);
+            l0tab = map_domain_page(page_to_mfn(page));
+            memset(l0tab, 0, PAGE_SIZE );
+            l1e = l1tab[l1_table_offset(va)] =
+                l1e_from_page(page, __PAGE_HYPERVISOR);
+        }
+        else if ( l0tab == NULL)
+            l0tab = map_domain_page(l1e_get_pfn(l1e));
+
+        l0tab[i & ((1 << PAGETABLE_ORDER) - 1) ] = pfn;
+        list_ent = frame_table[pfn].list.next;
+        va += sizeof(pfn);
     }
 
-    list_ent = d->xenpage_list.next;
-    while ( list_ent != &d->xenpage_list )
+    unmap_domain_page(l2tab);
+    unmap_domain_page(l1tab);
+    unmap_domain_page(l0tab);
+
+    return 1;
+}
+
+static void 
+free_p2m_table(struct vcpu *v)
+{
+    unsigned long va;
+    l2_pgentry_t *l2tab;
+    l1_pgentry_t *l1tab;
+    l2_pgentry_t l2e;
+    l1_pgentry_t l1e;
+
+    ASSERT ( pagetable_get_pfn(v->arch.monitor_table) );
+
+    l2tab = map_domain_page(
+        pagetable_get_pfn(v->arch.monitor_table));
+
+    for ( va = RO_MPT_VIRT_START; va < RO_MPT_VIRT_END; )
     {
-        page = list_entry(list_ent, struct page_info, list);
-        mfn = page_to_mfn(page);
-        pfn = get_gpfn_from_mfn(mfn);
-        if ( (pfn != INVALID_M2P_ENTRY) &&
-             (pfn < (1u<<20)) )
+        int i;
+
+        l2e = l2tab[l2_table_offset(va)];
+        if ( l2e_get_flags(l2e) & _PAGE_PRESENT )
         {
-            set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache);
+            l1tab = map_domain_page(l2e_get_pfn(l2e));
+            for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++)
+            {
+                l1e = l1tab[l1_table_offset(va)];
+
+                if ( l1e_get_flags(l1e) & _PAGE_PRESENT )
+                    free_domheap_page(mfn_to_page(l1e_get_pfn(l1e)));
+                va += PAGE_SIZE; 
+            }
+            unmap_domain_page(l1tab);
+            free_domheap_page(mfn_to_page(l2e_get_pfn(l2e)));
         }
+    }
+    unmap_domain_page(l2tab);
+}
+
+int shadow_direct_map_fault(unsigned long vpa, struct cpu_user_regs *regs)
+{
+    struct vcpu *v = current;
+    struct domain *d = v->domain;
+    l2_pgentry_t sl2e;
+    l1_pgentry_t sl1e;
+    l1_pgentry_t *sple = NULL;
+    unsigned long mfn, smfn;
+    struct page_info *page;
+
+    /*
+     * If the faulting address is within the MMIO range, we continue
+     * on handling the #PF as such.
+     */
+    if ( (mfn = get_mfn_from_gpfn(vpa >> PAGE_SHIFT)) == INVALID_MFN )
+    {
+         goto fail;
+    }
+
+    shadow_lock(d);
+
+    __shadow_get_l2e(v, vpa, &sl2e);
+
+   if ( !(l2e_get_flags(sl2e) & _PAGE_PRESENT) )
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto fail;
+
+        smfn = page_to_mfn(page);
+        sl2e = l2e_from_pfn(smfn, __PAGE_HYPERVISOR | _PAGE_USER);
+        __shadow_set_l2e(v, vpa, sl2e);
+    }
+
+    sple = (l1_pgentry_t *)map_domain_page(l2e_get_pfn(sl2e));
+    sl1e = sple[l1_table_offset(vpa)];
 
-        list_ent = page->list.next;
+    if ( !(l1e_get_flags(sl1e) & _PAGE_PRESENT) )
+    {
+        sl1e = l1e_from_pfn(mfn, __PAGE_HYPERVISOR | _PAGE_USER);
+        sple[l1_table_offset(vpa)] = sl1e;
     }
+    unmap_domain_page(sple);
+    shadow_unlock(d);
 
-    domain_mmap_cache_destroy(&l2cache);
-    domain_mmap_cache_destroy(&l1cache);
+    return EXCRET_fault_fixed;
 
+fail:
+    return 0;
+}
+
+
+int shadow_direct_map_init(struct vcpu *v)
+{
+    struct page_info *page;
+    l2_pgentry_t *root;
+
+    if ( !(page = alloc_domheap_page(NULL)) )
+        goto fail;
+
+    root = map_domain_page_global(page_to_mfn(page));
+    memset(root, 0, PAGE_SIZE);
+
+    v->domain->arch.phys_table = mk_pagetable(page_to_maddr(page));
+    /* 
+     * We need to set shadow_vtable to get __shadow_set/get_xxx
+     * working
+     */
+    v->arch.shadow_vtable = (l2_pgentry_t *) root;
+    v->arch.shadow_table = mk_pagetable(0);
     return 1;
+
+fail:
+    return 0;
 }
 
-static void
-free_p2m_table(struct domain *d)
+void shadow_direct_map_clean(struct vcpu *v)
 {
-    // uh, this needs some work...  :)
-    BUG();
+    int i;
+    l2_pgentry_t *l2e;
+
+    ASSERT ( v->arch.shadow_vtable );
+
+    l2e = v->arch.shadow_vtable;
+
+    for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
+    {
+        if ( l2e_get_flags(l2e[i]) & _PAGE_PRESENT )
+            free_domheap_page(mfn_to_page(l2e_get_pfn(l2e[i])));
+    }
+
+    free_domheap_page(
+            mfn_to_page(pagetable_get_pfn(v->domain->arch.phys_table)));
+
+    unmap_domain_page_global(v->arch.shadow_vtable);
+    v->arch.shadow_vtable = 0;
+    v->domain->arch.phys_table = mk_pagetable(0);
 }
 
 int __shadow_mode_enable(struct domain *d, unsigned int mode)
@@ -1092,11 +1238,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode)
         xfree(d->arch.shadow_dirty_bitmap);
         d->arch.shadow_dirty_bitmap = NULL;
     }
-    if ( (new_modes & SHM_translate) && !(new_modes & SHM_external) &&
-         pagetable_get_paddr(d->arch.phys_table) )
-    {
-        free_p2m_table(d);
-    }
+
     return -ENOMEM;
 }
 
index 29d7a8597999fb3015c706d2855df2b26419c809..e57f5a68378a111c755461109ced26f17f60053f 100644 (file)
 #if CONFIG_PAGING_LEVELS == 4
 extern struct shadow_ops MODE_F_HANDLER;
 extern struct shadow_ops MODE_D_HANDLER;
+
+static void free_p2m_table(struct vcpu *v);
 #endif
 
 extern struct shadow_ops MODE_A_HANDLER;
 
 #define SHADOW_MAX_GUEST32(_encoded) ((L1_PAGETABLE_ENTRIES_32 - 1) - ((_encoded) >> 16))
+
+
+int shadow_direct_map_init(struct vcpu *v)
+{
+    struct page_info *page;
+    l3_pgentry_t *root;
+
+    if ( !(page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA)) )
+        goto fail;
+
+    root = map_domain_page_global(page_to_mfn(page));
+    memset(root, 0, PAGE_SIZE);
+    root[PAE_SHADOW_SELF_ENTRY] = l3e_from_page(page, __PAGE_HYPERVISOR);
+
+    v->domain->arch.phys_table = mk_pagetable(page_to_maddr(page));
+    /* 
+     * We need to set shadow_vtable to get __shadow_set/get_xxx
+     * working
+     */
+    v->arch.shadow_vtable = (l2_pgentry_t *) root;
+
+    return 1;
+    
+fail:
+    return 0;
+}
+
+static void shadow_direct_map_clean(struct vcpu *v)
+{
+    l2_pgentry_t *l2e;
+    l3_pgentry_t *l3e;
+    int i, j;
+
+    ASSERT ( v->arch.shadow_vtable );
+
+    l3e = (l3_pgentry_t *) v->arch.shadow_vtable;
+    
+    for ( i = 0; i < PAE_L3_PAGETABLE_ENTRIES; i++ )
+    {
+        if ( l3e_get_flags(l3e[i]) & _PAGE_PRESENT )
+        {
+            l2e = map_domain_page(l3e_get_pfn(l3e[i]));
+
+            for ( j = 0; j < L2_PAGETABLE_ENTRIES; j++ )
+            {
+                if ( l2e_get_flags(l2e[j]) & _PAGE_PRESENT )
+                    free_domheap_page(mfn_to_page(l2e_get_pfn(l2e[j])));
+            }
+            unmap_domain_page(l2e);
+            free_domheap_page(mfn_to_page(l3e_get_pfn(l3e[i])));
+        }
+    }
+
+    free_domheap_page(
+        mfn_to_page(pagetable_get_pfn(v->domain->arch.phys_table)));
+
+    unmap_domain_page_global(v->arch.shadow_vtable);
+    v->arch.shadow_vtable = 0;
+    v->domain->arch.phys_table = mk_pagetable(0);
+}
+
 /****************************************************************************/
 /************* export interface functions ***********************************/
 /****************************************************************************/
@@ -49,8 +112,13 @@ extern struct shadow_ops MODE_A_HANDLER;
 
 int shadow_set_guest_paging_levels(struct domain *d, int levels)
 {
+    struct vcpu *v = current;
     shadow_lock(d);
 
+    if ( shadow_mode_translate(d) && 
+         !(pagetable_get_paddr(v->domain->arch.phys_table)) )
+         shadow_direct_map_clean(v);
+
     switch(levels) {
 #if CONFIG_PAGING_LEVELS >= 4
     case 4:
@@ -171,7 +239,7 @@ free_shadow_tables(struct domain *d, unsigned long smfn, u32 level)
     if ( d->arch.ops->guest_paging_levels == PAGING_L2 )
     {
         struct page_info *page = mfn_to_page(smfn);
-        for ( i = 0; i < PDP_ENTRIES; i++ )
+        for ( i = 0; i < PAE_L3_PAGETABLE_ENTRIES; i++ )
         {
             if ( entry_get_flags(ple[i]) & _PAGE_PRESENT )
                 free_fake_shadow_l2(d,entry_get_pfn(ple[i]));
@@ -229,48 +297,12 @@ free_shadow_tables(struct domain *d, unsigned long smfn, u32 level)
 #endif
 
 #if CONFIG_PAGING_LEVELS == 4
-/*
- * Convert PAE 3-level page-table to 4-level page-table
- */
-static pagetable_t page_table_convert(struct domain *d)
-{
-    struct page_info *l4page, *l3page;
-    l4_pgentry_t *l4;
-    l3_pgentry_t *l3, *pae_l3;
-    int i;
-
-    l4page = alloc_domheap_page(NULL);
-    if (l4page == NULL)
-        domain_crash_synchronous();
-    l4 = map_domain_page(page_to_mfn(l4page));
-    memset(l4, 0, PAGE_SIZE);
-
-    l3page = alloc_domheap_page(NULL);
-    if (l3page == NULL)
-        domain_crash_synchronous();
-    l3 = map_domain_page(page_to_mfn(l3page));
-    memset(l3, 0, PAGE_SIZE);
-
-    l4[0] = l4e_from_page(l3page, __PAGE_HYPERVISOR);
-
-    pae_l3 = map_domain_page(pagetable_get_pfn(d->arch.phys_table));
-    for (i = 0; i < PDP_ENTRIES; i++)
-        l3[i] = l3e_from_pfn(l3e_get_pfn(pae_l3[i]), __PAGE_HYPERVISOR);
-    unmap_domain_page(pae_l3);
-
-    unmap_domain_page(l4);
-    unmap_domain_page(l3);
-
-    return mk_pagetable(page_to_maddr(l4page));
-}
-
 static void alloc_monitor_pagetable(struct vcpu *v)
 {
     unsigned long mmfn;
     l4_pgentry_t *mpl4e;
     struct page_info *mmfn_info;
     struct domain *d = v->domain;
-    pagetable_t phys_table;
 
     ASSERT(!pagetable_get_paddr(v->arch.monitor_table)); /* we should only get called once */
 
@@ -284,13 +316,13 @@ static void alloc_monitor_pagetable(struct vcpu *v)
         l4e_from_paddr(__pa(d->arch.mm_perdomain_l3), __PAGE_HYPERVISOR);
 
     /* map the phys_to_machine map into the per domain Read-Only MPT space */
-    phys_table = page_table_convert(d);
-    mpl4e[l4_table_offset(RO_MPT_VIRT_START)] =
-        l4e_from_paddr(pagetable_get_paddr(phys_table),
-                       __PAGE_HYPERVISOR);
 
     v->arch.monitor_table = mk_pagetable(mmfn << PAGE_SHIFT);
     v->arch.monitor_vtable = (l2_pgentry_t *) mpl4e;
+    mpl4e[l4_table_offset(RO_MPT_VIRT_START)] = l4e_empty();
+
+    if ( v->vcpu_id == 0 )
+        alloc_p2m_table(d);
 }
 
 void free_monitor_pagetable(struct vcpu *v)
@@ -300,6 +332,12 @@ void free_monitor_pagetable(struct vcpu *v)
     /*
      * free monitor_table.
      */
+    if ( v->vcpu_id == 0 )
+        free_p2m_table(v);
+
+    /*
+     * Then free monitor_table.
+     */
     mfn = pagetable_get_pfn(v->arch.monitor_table);
     unmap_domain_page_global(v->arch.monitor_vtable);
     free_domheap_page(mfn_to_page(mfn));
@@ -307,7 +345,6 @@ void free_monitor_pagetable(struct vcpu *v)
     v->arch.monitor_table = mk_pagetable(0);
     v->arch.monitor_vtable = 0;
 }
-
 #elif CONFIG_PAGING_LEVELS == 3
 
 static void alloc_monitor_pagetable(struct vcpu *v)
@@ -319,91 +356,6 @@ void free_monitor_pagetable(struct vcpu *v)
 {
     BUG(); /* PAE not implemented yet */
 }
-
-#elif CONFIG_PAGING_LEVELS == 2
-
-static void alloc_monitor_pagetable(struct vcpu *v)
-{
-    unsigned long mmfn;
-    l2_pgentry_t *mpl2e;
-    struct page_info *mmfn_info;
-    struct domain *d = v->domain;
-    int i;
-
-    ASSERT(pagetable_get_paddr(v->arch.monitor_table) == 0);
-
-    mmfn_info = alloc_domheap_page(NULL);
-    ASSERT(mmfn_info != NULL);
-
-    mmfn = page_to_mfn(mmfn_info);
-    mpl2e = (l2_pgentry_t *)map_domain_page_global(mmfn);
-    memset(mpl2e, 0, PAGE_SIZE);
-
-    memcpy(&mpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE], 
-           &idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
-           HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
-
-    for ( i = 0; i < PDPT_L2_ENTRIES; i++ )
-        mpl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] =
-            l2e_from_page(virt_to_page(d->arch.mm_perdomain_pt) + i,
-                          __PAGE_HYPERVISOR);
-
-    // map the phys_to_machine map into the Read-Only MPT space for this domain
-    mpl2e[l2_table_offset(RO_MPT_VIRT_START)] =
-        l2e_from_paddr(pagetable_get_paddr(d->arch.phys_table),
-                       __PAGE_HYPERVISOR);
-
-    // Don't (yet) have mappings for these...
-    // Don't want to accidentally see the idle_pg_table's linear mapping.
-    //
-    mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)] = l2e_empty();
-    mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] = l2e_empty();
-
-    v->arch.monitor_table = mk_pagetable(mmfn << PAGE_SHIFT);
-    v->arch.monitor_vtable = mpl2e;
-}
-
-/*
- * Free the pages for monitor_table and hl2_table
- */
-void free_monitor_pagetable(struct vcpu *v)
-{
-    l2_pgentry_t *mpl2e, hl2e, sl2e;
-    unsigned long mfn;
-
-    ASSERT( pagetable_get_paddr(v->arch.monitor_table) );
-
-    mpl2e = v->arch.monitor_vtable;
-
-    /*
-     * First get the mfn for hl2_table by looking at monitor_table
-     */
-    hl2e = mpl2e[l2_table_offset(LINEAR_PT_VIRT_START)];
-    if ( l2e_get_flags(hl2e) & _PAGE_PRESENT )
-    {
-        mfn = l2e_get_pfn(hl2e);
-        ASSERT(mfn);
-        put_shadow_ref(mfn);
-    }
-
-    sl2e = mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)];
-    if ( l2e_get_flags(sl2e) & _PAGE_PRESENT )
-    {
-        mfn = l2e_get_pfn(sl2e);
-        ASSERT(mfn);
-        put_shadow_ref(mfn);
-    }
-
-    /*
-     * Then free monitor_table.
-     */
-    mfn = pagetable_get_pfn(v->arch.monitor_table);
-    unmap_domain_page_global(v->arch.monitor_vtable);
-    free_domheap_page(mfn_to_page(mfn));
-
-    v->arch.monitor_table = mk_pagetable(0);
-    v->arch.monitor_vtable = 0;
-}
 #endif
 
 static void
@@ -942,14 +894,6 @@ void __shadow_mode_disable(struct domain *d)
 }
 
 
-static void
-free_p2m_table(struct domain *d)
-{
-    // uh, this needs some work...  :)
-    BUG();
-}
-
-
 int __shadow_mode_enable(struct domain *d, unsigned int mode)
 {
     struct vcpu *v;
@@ -1143,11 +1087,7 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode)
         xfree(d->arch.shadow_dirty_bitmap);
         d->arch.shadow_dirty_bitmap = NULL;
     }
-    if ( (new_modes & SHM_translate) && !(new_modes & SHM_external) &&
-         pagetable_get_paddr(d->arch.phys_table) )
-    {
-        free_p2m_table(d);
-    }
+
     return -ENOMEM;
 }
 
@@ -1375,58 +1315,222 @@ int
 alloc_p2m_table(struct domain *d)
 {
     struct list_head *list_ent;
-    struct page_info *page, *l2page;
-    l2_pgentry_t *l2;
-    unsigned long mfn, pfn;
-    struct domain_mmap_cache l1cache, l2cache;
+    unsigned long va = RO_MPT_VIRT_START; /*  phys_to_machine_mapping */
+//    unsigned long va = PML4_ADDR(264);
 
-    l2page = alloc_domheap_page(NULL);
-    if ( l2page == NULL )
-        return 0;
+#if CONFIG_PAGING_LEVELS >= 4
+    l4_pgentry_t *l4tab = NULL;
+    l4_pgentry_t l4e = { 0 };
+#endif
+#if CONFIG_PAGING_LEVELS >= 3
+    l3_pgentry_t *l3tab = NULL;
+    l3_pgentry_t l3e = { 0 };
+#endif
+    l2_pgentry_t *l2tab = NULL;
+    l1_pgentry_t *l1tab = NULL;
+    unsigned long *l0tab = NULL;
+    l2_pgentry_t l2e = { 0 };
+    l1_pgentry_t l1e = { 0 };
 
-    domain_mmap_cache_init(&l1cache);
-    domain_mmap_cache_init(&l2cache);
+    unsigned long pfn;
+    int i;
+
+    ASSERT ( pagetable_get_pfn(d->vcpu[0]->arch.monitor_table) );
 
-    d->arch.phys_table = mk_pagetable(page_to_maddr(l2page));
-    l2 = map_domain_page_with_cache(page_to_mfn(l2page), &l2cache);
-    memset(l2, 0, PAGE_SIZE);
-    unmap_domain_page_with_cache(l2, &l2cache);
+#if CONFIG_PAGING_LEVELS >= 4
+    l4tab = map_domain_page(
+        pagetable_get_pfn(d->vcpu[0]->arch.monitor_table));
+#endif
+#if CONFIG_PAGING_LEVELS >= 3
+    l3tab = map_domain_page(
+        pagetable_get_pfn(d->vcpu[0]->arch.monitor_table));
+#endif
 
     list_ent = d->page_list.next;
-    while ( list_ent != &d->page_list )
+
+    for ( i = 0; list_ent != &d->page_list; i++ ) 
     {
+        struct page_info *page;
+
         page = list_entry(list_ent, struct page_info, list);
-        mfn = page_to_mfn(page);
-        pfn = get_gpfn_from_mfn(mfn);
-        ASSERT(pfn != INVALID_M2P_ENTRY);
-        ASSERT(pfn < (1u<<20));
+        pfn = page_to_mfn(page);
+
+#if CONFIG_PAGING_LEVELS >= 4
+        l4e = l4tab[l4_table_offset(va)];
+        if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) 
+        {
+            page = alloc_domheap_page(NULL);
 
-        set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache);
+            if ( !l3tab )
+                unmap_domain_page(l3tab);
 
-        list_ent = page->list.next;
-    }
+            l3tab = map_domain_page(page_to_mfn(page));
+            memset(l3tab, 0, PAGE_SIZE);
+            l4e = l4tab[l4_table_offset(va)] = 
+                l4e_from_page(page, __PAGE_HYPERVISOR);
+        } 
+        else if ( l3tab == NULL)
+            l3tab = map_domain_page(l4e_get_pfn(l4e));
+#endif
+        l3e = l3tab[l3_table_offset(va)];
+        if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ) 
+        {
+            page = alloc_domheap_page(NULL);
+            if ( !l2tab )
+                unmap_domain_page(l2tab);
+
+            l2tab = map_domain_page(page_to_mfn(page));
+            memset(l2tab, 0, PAGE_SIZE);
+            l3e = l3tab[l3_table_offset(va)] = 
+                l3e_from_page(page, __PAGE_HYPERVISOR);
+        } 
+        else if ( l2tab == NULL) 
+            l2tab = map_domain_page(l3e_get_pfn(l3e));
 
-    list_ent = d->xenpage_list.next;
-    while ( list_ent != &d->xenpage_list )
-    {
-        page = list_entry(list_ent, struct page_info, list);
-        mfn = page_to_mfn(page);
-        pfn = get_gpfn_from_mfn(mfn);
-        if ( (pfn != INVALID_M2P_ENTRY) &&
-             (pfn < (1u<<20)) )
+        l2e = l2tab[l2_table_offset(va)];
+        if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) 
         {
-            set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache);
+            page = alloc_domheap_page(NULL);
+
+            if ( !l1tab )
+                unmap_domain_page(l1tab);
+            
+            l1tab = map_domain_page(page_to_mfn(page));
+            memset(l1tab, 0, PAGE_SIZE);
+            l2e = l2tab[l2_table_offset(va)] = 
+                l2e_from_page(page, __PAGE_HYPERVISOR);
+        } 
+        else if ( l1tab == NULL) 
+            l1tab = map_domain_page(l2e_get_pfn(l2e));
+
+        l1e = l1tab[l1_table_offset(va)];
+        if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) ) 
+        {
+            page = alloc_domheap_page(NULL);
+            if ( !l0tab )
+                unmap_domain_page(l0tab);
+
+            l0tab = map_domain_page(page_to_mfn(page));
+            memset(l0tab, 0, PAGE_SIZE);
+            l1e = l1tab[l1_table_offset(va)] = 
+                l1e_from_page(page, __PAGE_HYPERVISOR);
         }
+        else if ( l0tab == NULL) 
+            l0tab = map_domain_page(l1e_get_pfn(l1e));
 
-        list_ent = page->list.next;
+        l0tab[i & ((1 << PAGETABLE_ORDER) - 1) ] = pfn;
+        list_ent = frame_table[pfn].list.next;
+        va += sizeof (pfn);
     }
-
-    domain_mmap_cache_destroy(&l2cache);
-    domain_mmap_cache_destroy(&l1cache);
+#if CONFIG_PAGING_LEVELS >= 4
+    unmap_domain_page(l4tab);
+#endif
+#if CONFIG_PAGING_LEVELS >= 3
+    unmap_domain_page(l3tab);
+#endif
+    unmap_domain_page(l2tab);
+    unmap_domain_page(l1tab);
+    unmap_domain_page(l0tab);
 
     return 1;
 }
 
+#if CONFIG_PAGING_LEVELS == 4
+static void
+free_p2m_table(struct vcpu *v)
+{
+    unsigned long va;
+    l1_pgentry_t *l1tab;
+    l1_pgentry_t l1e;
+    l2_pgentry_t *l2tab;
+    l2_pgentry_t l2e;
+#if CONFIG_PAGING_LEVELS >= 3
+    l3_pgentry_t *l3tab; 
+    l3_pgentry_t l3e;
+    int i3;
+#endif
+#if CONFIG_PAGING_LEVELS == 4
+    l4_pgentry_t *l4tab; 
+    l4_pgentry_t l4e;
+#endif
+
+    ASSERT ( pagetable_get_pfn(v->arch.monitor_table) );
+
+#if CONFIG_PAGING_LEVELS == 4
+    l4tab = map_domain_page(
+        pagetable_get_pfn(v->arch.monitor_table));
+#endif
+#if CONFIG_PAGING_LEVELS == 3
+    l3tab = map_domain_page(
+        pagetable_get_pfn(v->arch.monitor_table));
+#endif
+
+    for ( va = RO_MPT_VIRT_START; va < RO_MPT_VIRT_END; )
+    {
+#if CONFIG_PAGING_LEVELS == 4
+        l4e = l4tab[l4_table_offset(va)];
+
+        if ( l4e_get_flags(l4e) & _PAGE_PRESENT )
+        {
+            l3tab = map_domain_page(l4e_get_pfn(l4e));
+#endif
+            for ( i3 = 0; i3 < L1_PAGETABLE_ENTRIES; i3++ )
+            {
+                l3e = l3tab[l3_table_offset(va)];
+                if ( l3e_get_flags(l3e) & _PAGE_PRESENT )
+                {
+                    int i2;
+
+                    l2tab = map_domain_page(l3e_get_pfn(l3e));
+
+                    for ( i2 = 0; i2 < L1_PAGETABLE_ENTRIES; i2++ )
+                    {
+                        l2e = l2tab[l2_table_offset(va)];
+                        if ( l2e_get_flags(l2e) & _PAGE_PRESENT )
+                        {
+                            int i1;
+
+                            l1tab = map_domain_page(l2e_get_pfn(l2e));
+
+                            for ( i1 = 0; i1 < L1_PAGETABLE_ENTRIES; i1++ )
+                            {
+                                l1e = l1tab[l1_table_offset(va)];
+
+                                if ( l1e_get_flags(l1e) & _PAGE_PRESENT )
+                                    free_domheap_page(mfn_to_page(l1e_get_pfn(l1e)));
+
+                                va += 1UL << L1_PAGETABLE_SHIFT;
+                            }
+                            unmap_domain_page(l1tab);
+                            free_domheap_page(mfn_to_page(l2e_get_pfn(l2e)));
+                        }
+                        else
+                            va += 1UL << L2_PAGETABLE_SHIFT;
+                    }
+                    unmap_domain_page(l2tab);
+                    free_domheap_page(mfn_to_page(l3e_get_pfn(l3e)));
+                }
+                else
+                    va += 1UL << L3_PAGETABLE_SHIFT;
+            }
+#if CONFIG_PAGING_LEVELS == 4
+            unmap_domain_page(l3tab);
+            free_domheap_page(mfn_to_page(l4e_get_pfn(l4e)));
+        }
+        else
+            va += 1UL << L4_PAGETABLE_SHIFT;
+#endif
+    }
+
+#if CONFIG_PAGING_LEVELS == 4
+    unmap_domain_page(l4tab);
+#endif
+#if CONFIG_PAGING_LEVELS == 3
+    unmap_domain_page(l3tab);
+#endif
+}
+#endif
+
 void shadow_l1_normal_pt_update(
     struct domain *d,
     paddr_t pa, l1_pgentry_t gpte,
@@ -1770,6 +1874,7 @@ void clear_all_shadow_status(struct domain *d)
     shadow_unlock(d);
 }
 
+
 /*
  * Local variables:
  * mode: C
index 759e0adb1837e4ea5a63b5b6218b257024f02323..468427b099bf4b959ecf0b34be176bc22a40798b 100644 (file)
@@ -279,14 +279,9 @@ int check_descriptor(struct desc_struct *d);
 static inline unsigned long get_mfn_from_gpfn(unsigned long pfn)
 {
     unsigned long mfn;
-    l1_pgentry_t pte;
-
-    if ( (__copy_from_user(&pte, &phys_to_machine_mapping[pfn],
-                           sizeof(pte)) == 0) &&
-         (l1e_get_flags(pte) & _PAGE_PRESENT) )
-        mfn = l1e_get_pfn(pte);
-    else
-        mfn = INVALID_MFN;
+
+    if ( __copy_from_user(&mfn, &phys_to_machine_mapping[pfn], sizeof(mfn)) )
+       mfn = INVALID_MFN;
 
     return mfn;
 }
index 7149e9945d79392a418691e3735d09fcd1889bdc..773e306f9961ae1bb2d0fb01897f06c79e441b14 100644 (file)
@@ -115,7 +115,12 @@ do {                                            \
 #define SHADOW_ENCODE_MIN_MAX(_min, _max) ((((GUEST_L1_PAGETABLE_ENTRIES - 1) - (_max)) << 16) | (_min))
 #define SHADOW_MIN(_encoded) ((_encoded) & ((1u<<16) - 1))
 #define SHADOW_MAX(_encoded) ((GUEST_L1_PAGETABLE_ENTRIES - 1) - ((_encoded) >> 16))
-
+#if CONFIG_PAGING_LEVELS == 2
+extern void shadow_direct_map_clean(struct vcpu *v);
+#endif
+extern int shadow_direct_map_init(struct vcpu *v);
+extern int shadow_direct_map_fault(
+    unsigned long vpa, struct cpu_user_regs *regs);
 extern void shadow_mode_init(void);
 extern int shadow_mode_control(struct domain *p, dom0_shadow_control_t *sc);
 extern int shadow_fault(unsigned long va, struct cpu_user_regs *regs);
index 2f12f0676281d555e395527463a0f153a6c0fa34..a8422b584d627f00092411d75e844a9589ff5807 100644 (file)
@@ -92,7 +92,7 @@ typedef struct { intpte_t lo; } pgentry_64_t;
         ( !!(((x).lo ^ (y).lo) & ((PADDR_MASK&PAGE_MASK)|put_pte_flags(flags))) )
 
 #define PAE_SHADOW_SELF_ENTRY   259
-#define PDP_ENTRIES   4
+#define PAE_L3_PAGETABLE_ENTRIES   4
 
 static inline int  table_offset_64(unsigned long va, int level)
 {
index 3ab2d581cfd72605fa422855a26a3c09b2ae7019..bde99e042727d67f7a7ae93ab76d5d09bc75c7f9 100644 (file)
 
 #ifndef _XEN_SHADOW_PUBLIC_H
 #define _XEN_SHADOW_PUBLIC_H
-#if CONFIG_PAGING_LEVELS >= 3
-#define MFN_PINNED(_x) (mfn_to_page(_x)->u.inuse.type_info & PGT_pinned)
 
 extern int alloc_p2m_table(struct domain *d);
 
+#if CONFIG_PAGING_LEVELS >= 3
+#define MFN_PINNED(_x) (mfn_to_page(_x)->u.inuse.type_info & PGT_pinned)
+
 extern void shadow_sync_and_drop_references(
       struct domain *d, struct page_info *page);
 extern void shadow_drop_references(